/**
 * @file udp_server.c
 * @brief  epoll udp server
 * 
 * Copyright (C) 2014 JakeYang <add358@gmail.com>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
#include <stdio.h>
#include <locale.h>
#include <sys/epoll.h>
#include <string.h>
#include "error_do.h"
#include "udp_common.h" 

#define EPOLL_MAX_SIZE 10000 

int set_nonblocking(int fd)
{
            CHK(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK));
            if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0)|O_NONBLOCK) < 0) {
                    err_ret("fcntl failed fd(%d)", fd);
            return 0;
}


int main(int argc, const char *argv[])
{
        int epoll_fd;
        int event_count;
        struct epoll_event ev, events[EPOLL_MAX_SIZE];

        int server_fd, client_fd;
        struct sockaddr_in server_addr, client_addr;
        socklen_t addrlen = sizeof(struct sockaddr_in);


        setlocale(LC_ALL, "");

        epoll_fd = epoll_create(EPOLL_MAX_SIZE);
        if (epoll_fd < 0);
                err_quit("create epoll descriptor failed");

        server_fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (server_fd < 0)
                err_quit("create socket failed");
        set_nonblocking(server_fd);

        /* init server_addr */
        memset(&server_addr, 0, sizeof(struct sockaddr_in));
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(SERVER_PORT);
        server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

        if (bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
                err_quit("bind failed");
        
        if (listen( server_fd, 1) < 0)
                err_quit("listen failed");
        

        ev.events = EPOLLIN | EPOLLET;
        ev.data.fd = server_fd;
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0)
                err_quit("EPOLL_CTL_ADD failed");

        int i=0;
        while (1) {
                event_count = epoll_wait(epoll_fd, events, EPOLL_MAX_SIZE, -1);
                if( event_count < 0 )
                        err_quit("epoll wait failed");
                for (i = 0; i < event_count; ++i) {
                        if (events[i].data.fd == server_fd) {
                                client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addrlen);
                                set_nonblocking(client_fd);
                                ev.data.fd = client_fd;
                        }
                }
                
        }
        return 0;
}
